// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or  modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.

var Backbone = require("backbone");
var CommentFormView = require("../views/comment-form");
var CommentsCollection = require("../collections/comments");
var Constants = require("../util/constants");
var ConversationInfoSlideView = require("../views/conversationInfoSlideView");
var ConversationStatsHeader = require("../views/conversation-stats-header");
var ConversationTabsView = require("../views/conversationTabs");
var ConversationView = require("../views/conversation");
var DivisiveCommentsView = require("../views/DivisiveCommentsView");
var display = require("../util/display");
var eb = require("../eventBus");
var GroupSelectionView = require("../views/groupSelectionView");
var { markdown } = require("markdown");
var ParticipantModel = require("../models/participant");
var polisLogoBase64 = require("../images/polis_logo");
var preloadHelper = require("../util/preloadHelper");
var ReadReactView = require("../views/ReadReactView");
var Strings = require("../strings");
var template = require("../templates/participation.handlebars");
var TopCommentsView = require("../views/TopCommentsView");
var Utils = require("../util/utils");
var VisView = require("../lib/VisView");
var VoteMoreView = require("../views/voteMoreView");
var WritingTipsView = require("../views/writingTips");
var $ = require("jquery");
var _ = require("lodash");

var VIS_SELECTOR = "#visualization_div";

var SHOULD_AUTO_CLICK_FIRST_COMMENT = false;

var VIS_MODE_VIS = 0;
var VIS_MODE_WAITING = 1;
var VIS_MODE_VOTEMORE = 2;
var VIS_MODE_TUT = 3;

var MIN_PTPTS = 7;

var useAboveVisTutorial = false;
var useVoteMoreBlocker = false;

var isIE8 = Utils.isIE8();
var isMobile = Utils.isMobile();

function shouldHideVisWhenWriteTabShowing() {
  return true;
  // return shouldShowVisUnderTabs();
}

function shouldMoveVis() {
  return false;
}

module.exports = ConversationView.extend({
  name: "participationView",
  template: template,
  className: "participationView clickDeselectsHull",
  events: {
    "click .hideOnClick": "hideOnClick",
    "click #helpTextGroupsExpand": "expandHelpTextGroups"
  },
  firstMathPollResultDeferred: $.Deferred(),
  shouldAffixVis: false,
  inVisLegendCounter: 0,
  onAnalyzeTabPopulated: function () {
    if (SHOULD_AUTO_CLICK_FIRST_COMMENT) {
      $(".query_result_item").first().trigger("click");
    }
  },
  expandHelpTextGroups: function () {
    $("#helpTextGroupsExpand").hide();
    $("#helpTextGroupsMore").show();
    return false;
  },
  hideVis: function () {
    $("#vis_sibling_bottom").hide();
  },
  showVis: function () {
    $("#vis_sibling_bottom").show();
  },
  hideWriteHints: function () {
    $("#write_hints_div").hide();
  },
  showWriteHints: function () {
    $("#write_hints_div").show();
  },
  allowMetadataFiltering: function () {
    return this.conversationTabs.onAnalyzeTab();
  },

  updateVoteRemaining: function () {
    if (useVoteMoreBlocker) {
      this.voteMoreModel.set("remaining", Math.max(0, 2 - this.votesByMe.length));
    }
  },

  emphasizeParticipants: function () {
    if (this.vis) {
      this.vis.emphasizeParticipants.apply(this, arguments);
    }
  },
  context: function () {
    var ctx = ConversationView.prototype.context.apply(this, arguments);
    ctx.use_background_content_class = display.xs();
    ctx.xs = display.xs();
    ctx.showNewButton = true;
    ctx.s = Strings;
    ctx.polis_bgcolor = "white"; //preload.firstConv.bgcolor || "#f7f7f7";
    ctx.hideHelp = !Utils.userCanSeeHelp() || window.preload.firstConv.help_type === 0;

    ctx.direction = Strings.direction ? Strings.direction : "ltr";
    // var md_content = "Hello.\n======\n* This is markdown.\n * It is fun\n * Love it or leave it.\n* This is [an example](http://example.com/ \"Title\") inline link.\n\n![Alt text](https://62e528761d0685343e1c-f3d1b99a743ffa4142d9d7f1978d9686.ssl.cf2.rackcdn.com/files/67396/width668/image-20141216-14144-1fmodw7.jpg)"
    var md_content = ctx.description || "";

    var html = markdown.toHTML(md_content);
    ctx.description = html;
    if (/^ *$/.test(ctx.description) || _.isNull(ctx.description) || ctx.description === "") {
      ctx.description = void 0;
    }
    if (/^ *$/.test(ctx.topic) || _.isNull(ctx.topic) || ctx.topic === "") {
      ctx.topic = void 0;
    }

    ctx.useBannerHeader = false; //!Utils.isInIframe();
    // ctx.showLogoAndBreadCrumbInHeader = ctx.context && !Utils.isInIframe();
    ctx.showLogoAndBreadCrumbInHeader = false;
    ctx.showLogoInHeader = false; //!Utils.isInIframe();

    // ctx.showLogoInFooter = !ctx.showLogoAndBreadCrumbInHeader;
    ctx.showLogoInFooter = false;

    ctx.no_vis = !Utils.userCanSeeVis() || ctx.vis_type === Constants.VIS_TYPE.OFF;
    ctx.no_write = ctx.write_type === 0 || !Utils.userCanWrite() || !ctx.is_active;
    ctx.no_voting = !Utils.userCanVote() || !ctx.is_active;
    ctx.no_topic = !Utils.userCanSeeTopic() || !ctx.topic || ctx.topic.length === 0;
    ctx.no_description = !Utils.userCanSeeDescription() || !ctx.description || ctx.description.length === 0;
    ctx.no_footer = !Utils.userCanSeeFooter();

    ctx.help_bgcolor = ctx.help_bgcolor || "#CAEAFF";
    ctx.help_color = ctx.help_color || "#3498DB";

    var temp = Strings.addPolisToYourSite;
    temp = temp.replace("{{URL}}", polisLogoBase64);
    ctx.addPolisToYourSite = temp;

    ctx.show_admin_button = false; //ctx.is_owner;

    ctx.show_top_comments = ctx.vis_type === Constants.VIS_TYPE.TOP_COMMENTS;
    ctx.show_divisive_comments = ctx.vis_type === Constants.VIS_TYPE.TOP_COMMENTS;

    ctx.show_pca_vis = ctx.vis_type === Constants.VIS_TYPE.PCA;
    return ctx;
  },

  convSub: function (params) {
    var that = this;
    this.serverClient.convSub(params).then(function (o) {
      that.subscribed = o.subscribed;
    });
  },
  isSubscribed: function (optionalCrappySetterModeValue) {
    if (!_.isUndefined(optionalCrappySetterModeValue)) {
      this.ptptModel.set("subscribed", optionalCrappySetterModeValue);
      return optionalCrappySetterModeValue;
    }
    return this.ptptModel.get("subscribed");
  },

  updateHeader: function () {
    if (!window.renderHeader) {
      console.error("window.renderHeader missing");
      return;
    }
    window.renderHeader(document.getElementById("header_root"), {
      user: window.preload.firstUser,
      is_owner: window.preload.firstConv.is_owner,
      conversation_id: this.conversation_id,
      is_embedded: window.isEmbedded()
    });
  },

  curationType: null,

  updateTopComments: function () {
    if (this.model.get("vis_type") !== Constants.VIS_TYPE.TOP_COMMENTS) {
      return;
    }
    var that = this;

    if (this.allCommentsCollection.length === 0) {
      // try again
      setTimeout(function () {
        that.updateTopComments();
      }, 200);
      return;
    }

    var ranking = {}; // tid -> ranking
    function getRanking(tid) {
      return ranking[tid] || 0;
    }

    if (Utils.getGroupAware()) {
      ranking = this.serverClient.getGroupAwareConsensus();
    } else {
      var temp = this.serverClient.getConsensus();
      var agree = temp.agree;
      for (var i = 0; i < agree.length; i++) {
        ranking[agree[i].tid] = agree[i]["p-success"];
      }
    }
    var groupVotes = this.serverClient.getGroupVotes("all");

    this.allCommentsCollection.each(function (c) {
      var tid = c.get("tid");
      c.set("rank", getRanking(tid));
    });

    var topComments = this.allCommentsCollection.clone().models;
    var divisiveComments = this.allCommentsCollection.clone().models;
    topComments.sort(function (a, b) {
      return b.attributes.rank - a.attributes.rank;
    });
    divisiveComments.sort(function (a, b) {
      return a.attributes.rank - b.attributes.rank;
    });
    topComments = topComments.slice(0, 5);
    divisiveComments = divisiveComments.slice(0, 5);

    _.each([topComments, divisiveComments], function (collection) {
      _.each(collection, function (c) {
        var tid = c.get("tid");
        var gv = groupVotes[tid];
        c.set("gv", gv);
        c.set("percentAgree", Math.round((100 * gv.agreed) / gv.saw));
        c.set("percentDisagree", Math.round((100 * gv.disagreed) / gv.saw));
        c.set("percentPassed", Math.round((100 * (gv.saw - gv.disagreed - gv.agreed)) / gv.saw));
        // c.set("percentAgree", gv.agreed + "/" + gv.saw);
      });
    });

    topComments.sort(function (a, b) {
      return b.attributes.percentAgree - a.attributes.percentAgree;
    });
    divisiveComments.sort(function (a, b) {
      return a.attributes.percentAgree - b.attributes.percentAgree;
    });

    // remove any items from divisive list that are also in top list
    var topTids = _.map(topComments, "tid");
    divisiveComments = _.filter(divisiveComments, function (c) {
      return topTids.indexOf(c.tid) >= 0;
    });

    this.topCommentsCollection.reset(topComments);
    this.divisiveCommentsCollection.reset(divisiveComments);
  },

  updateVis2: function () {
    var that = this;

    if (this.model.get("vis_type") !== Constants.VIS_TYPE.PCA) {
      return;
    }

    // TODO don't do a separate AJAX call for the comments.
    this.serverClient.getFancyComments().then(function (comments) {
      function doRenderVis() {
        var mathMain = that.serverClient.getMathMain();
        var tidsToShow = []; //that.serverClient.getVotedOnTids();
        if (_.isNull(that.curationType)) {
          // no-op
        } else if (that.curationType === "majority") {
          tidsToShow = [];
          Array.prototype.push.apply(
            tidsToShow,
            mathMain.consensus.agree.map(function (c) {
              return c.tid;
            })
          );
          Array.prototype.push.apply(
            tidsToShow,
            mathMain.consensus.disagree.map(function (c) {
              return c.tid;
            })
          );
        } else if (that.curationType === "differences") {
          // no-op
        } else if (_.isNumber(that.curationType)) {
          tidsToShow = [];
          var gid = that.curationType;
          Array.prototype.push.apply(
            tidsToShow,
            mathMain.repness[gid].map(function (c) {
              return c.tid;
            })
          );
        } else {
          console.error("unknown curationType:", that.curationType);
        }

        if (!window.renderVis) {
          console.error("window.renderVis missing");
          return;
        }
        window.renderVis(document.getElementById("vis2_root"), {
          Strings: Strings,
          math_main: mathMain,
          comments: comments,
          tidsToShow: tidsToShow,
          ptptois: that.serverClient.getParticipantsOfInterestIncludingSelf(),
          votesByMe: that.serverClient.getVotesByMe(),
          onVoteClicked: onVoteClicked,
          onCurationChange: onCurationChange
          // comments: this.allCommentsCollection.models,
        });
      }

      function onVoteClicked(o) {
        var dfd = $.Deferred().reject();
        if (o.vote === window.polisTypes.reactions.pull) {
          dfd = that.serverClient.agree(o.tid);
        } else if (o.vote === window.polisTypes.reactions.push) {
          dfd = that.serverClient.disagree(o.tid);
        } else if (o.vote === window.polisTypes.reactions.pass) {
          dfd = that.serverClient.pass(o.tid);
        }
        dfd.then(
          function () {
            that.serverClient.addToVotesByMe({
              vote: o.vote,
              tid: o.tid,
              conversation_id: that.conversation_id
            });
            doRenderVis();
          },
          function () {
            alert("error changing vote");
          }
        );
      }

      function onCurationChange(newCurationType) {
        that.curationType = newCurationType;
        doRenderVis();
      }

      doRenderVis();
    });
  },
  updateVisMode: function () {
    if (!this.vis) {
      return;
    }
    if (this.voteMoreModel.get("remaining") >= 1) {
      this.visModeModel.set("visMode", VIS_MODE_VOTEMORE);
    } else {
      this.visModeModel.set("visMode", VIS_MODE_VIS);
    }
  },
  updateLineToSelectedCluster: function (gid) {
    if (this.vis) {
      gid = _.isUndefined(gid) ? this.selectedGid : gid;
      this.vis.showLineToCluster(gid);
      // }
    }
  },
  shouldShowVisUnderTabs: function () {
    return (
      display.xs() /* || display.sm() */ && (this.conversationTabs.onAnalyzeTab() || this.conversationTabs.onGroupTab())
    );
  },
  initialize: function (options) {
    ConversationView.prototype.initialize.apply(this, arguments);
    var that = this;
    this.wipCommentFormText = options.wipCommentFormText;
    this.ptptModel = new ParticipantModel();

    // Handle null ptpt (anonymous participants aren't created until they vote)
    preloadHelper.firstPtptPromise
      .then(function (ptpt) {
        if (ptpt) {
          that.ptptModel.set(ptpt);
        } else {
          // Initialize empty participant model for anonymous users
          that.ptptModel.set({
            pid: -1,
            conversation_id: that.conversation_id,
            vote_count: 0,
            subscribed: false
          });
        }
      })
      .fail(function () {
        // Handle promise rejection - initialize empty participant model
        that.ptptModel.set({
          pid: -1,
          conversation_id: that.conversation_id,
          vote_count: 0,
          subscribed: false
        });
      });

    $.when(options.firstCommentPromise).then(function (c) {
      if (c && c.translations && c.translations.length) {
        c.translations = Utils.getBestTranslation(c.translations, Utils.uiLanguage());
      }
      that.doInit(options, c);
    });
  },
  doInit: function (options) {
    var vis;
    var that = this;
    var conversation_id = this.conversation_id;
    var serverClient = this.serverClient;

    // This is a wart. ServerClient should be initialized much earlier, probably as a singleton, and it should be responsible for fetching the first comment.
    serverClient.setNextCachedComment(options.firstCommentPromise);

    eb.on(eb.vote, function () {
      that.updateVis2();
      that.updateTopComments();
    });

    // initialize this first to ensure that the vote view is showing and populated ASAP
    this.readReactModel = new Backbone.Model();
    this.readReactView = this.addChild(
      new ReadReactView({
        firstCommentPromise: options.firstCommentPromise,
        serverClient: serverClient,
        model: this.readReactModel,
        conversationModel: this.model,
        votesByMe: this.votesByMe,
        // is_public: Utils.isShortConversationId(this.conversation_id),
        isSubscribed: function () {
          return that.isSubscribed.apply(that, arguments);
        },
        conversation_id: conversation_id
      })
    );

    this.topCommentsCollection = new CommentsCollection([]);
    this.topCommentsView = this.addChild(
      new TopCommentsView({
        collection: this.topCommentsCollection
      })
    );
    this.divisiveCommentsCollection = new CommentsCollection([]);
    this.divisiveCommentsView = this.addChild(
      new DivisiveCommentsView({
        collection: this.divisiveCommentsCollection
      })
    );

    // clicks to "the background" should delelect hulls.
    // This is important because the edge of the vis is not visible.
    $(document.body).on("click", function (e) {
      function maybeDeselectHull($node) {
        if (!$node) {
          return;
        }
        if ($node.hasClass("clickDeselectsHull")) {
          if (that.vis) {
            that.vis.deselect();
          }
          eb.trigger(eb.backgroundClicked);
          return;
        } else if ($node.hasClass("clickDoesNotDeselectHull")) {
          // we're in a subtree where clicking does not deselect hulls.
          // Done searching.
          return;
        } else if ($node.parent() && $node.parent().length) {
          // keep searching
          maybeDeselectHull($node.parent());
          return;
        }
      }

      maybeDeselectHull($(e.target));
    });

    eb.on(eb.deselectGroups, function () {
      if (that.vis) {
        that.vis.deselect();
      }
    });

    eb.on(eb.clusterSelectionChanged, function (gid) {
      that.selectedGid = gid;
      that.updateLineToSelectedCluster(gid);
      that.groupNamesModel.set({
        selectedGid: gid,
        infoSlidePaneViewActive: false
      });

      if (gid === -1) {
        if (vis) {
          vis.selectComment(null);
        }
        // $("#commentViewTab").click();

        if (that.conversationTabs.onGroupTab()) {
          // TODO check if needed
          // that.conversationTabs.gotoVoteTab();
          // that.conversationTabs.gotoAnalyzeTab();
        }
      }
    });
    eb.on(eb.backgroundClicked, function () {
      that.conversationTabs.gotoInfoPaneTab();
      that.groupSelectionView.gotoInfoPaneTab();
    });
    eb.on(eb.clusterClicked, function (gid) {
      if (_.isNumber(gid) && gid >= 0) {
        that.conversationTabs.gotoGroupTab();
        // that.tutorialModel.set("step", Infinity);
        // $("#groupTab").click();
        // $("#groupTab").tab("show");

        if (that.selectedGid === -1) {
          // on transition from no selection to selection
          // // ensure vis is showing when you click on a group, this also should ensure that the carousel is on-screen below the vis
          // if (isMobile) {
          //   $('html, body').animate({
          //     scrollTop: $("#visualization_parent_div").offset().top
          //   }, 100);
          // }
        }
      }

      that.onClusterTapped.apply(that, arguments);
    });

    eb.on(eb.queryResultsRendered, this.onAnalyzeTabPopulated.bind(this));

    this.conversationStatsHeader = new ConversationStatsHeader();

    // HTTP PATCH - model.save({patch: true})

    function onPersonUpdate(updatedNodes, newClusters, newParticipantCount) {
      that.firstMathPollResultDeferred.resolve();
      if (newParticipantCount >= MIN_PTPTS) {
        if ($("#vis_section:hidden")) {
          $("#vis_section").fadeIn(1000, function () {
            that.initPcaVis();
          });
        }
        $("#vis_help_label").show();
        $("#vis_not_yet_label").hide();
        eb.trigger(eb.visShown);
      } else {
        $("#vis_section").hide();
        $("#vis_help_label").hide();
        $("#vis_not_yet_label").show();
      }
      if (vis) {
        vis.upsertNode.apply(vis, arguments);
      }

      var newGroups = _.map(newClusters, function (c, index) {
        return {
          styles: "",
          name: Number(index) + 1,
          gid: Number(index)
        };
      });
      newGroups.push({
        name: display.xs() ? Strings.majorityOpinionShort : Strings.majorityOpinion,
        styles: "margin-left: 20px;",
        gid: -1
      });
      that.groupNamesModel.set("groups", newGroups);

      $(".participationCount").html(newParticipantCount + (newParticipantCount === 1 ? " person" : " people"));
      that.updateVis2();
      that.updateTopComments();
    }

    function configureGutters() {
      // if (display.xs()) {
      //   $("#controlTabs").addClass("no-gutter");
      // } else {
      //   $("#controlTabs").removeClass("no-gutter");
      // }
    }

    function moveVisToBottom() {
      if (shouldMoveVis()) {
        var $vis = that.$("#visualization_parent_div").detach();
        $("#vis_sibling_bottom").append($vis);
      }
    }

    function moveVisAboveQueryResults() {
      var $vis = that.$("#visualization_parent_div").detach();
      $("#vis_sibling_above_tab_content").append($vis);
    }

    function initPcaVis() {
      if (!Utils.supportsVis()) {
        // Don't show vis for weird devices (Gingerbread, etc)
        return;
      }

      var w = $("#visualization_div").width();
      var xOffset = 30;
      if (isIE8) {
        w = 500;
        // $("#visualization_div").width(w);
      }
      if (display.xs()) {
        xOffset = 0;
        w = $(document.body).width() - 30;
      }
      var h = w / 2;
      // $("#visualization_div").height(h);
      if (w === that.oldW && h === that.oldH) {
        return;
      }
      that.oldH = h;
      that.oldW = w;
      $("#visualization_div > .visualization").remove();
      // $(VIS_SELECTOR).html("").height(0);
      // $(VIS_SELECTOR).parent().css("display", "none");

      that.serverClient.removePersonUpdateListener(onPersonUpdate); // TODO REMOVE DUPLICATE
      vis = that.vis = new VisView({
        inVisLegendCounter: that.inVisLegendCounter,
        isIE8: isIE8,
        isMobile: isMobile,
        getCommentsForProjection: serverClient.getCommentsForProjection,
        getReactionsToComment: serverClient.getReactionsToComment,
        getPidToBidMapping: serverClient.getPidToBidMapping,
        getParticipantsOfInterestForGid: serverClient.getParticipantsOfInterestForGid,
        xOffset: xOffset,
        w: w,
        h: h,
        computeXySpans: Utils.computeXySpans,
        el_queryResultSelector: ".query_results_div",
        el: VIS_SELECTOR,
        getGroupNameForGid: function (gid) {
          var x = that.serverClient.getGroupInfo(gid);
          return x.count;
        }
      });
      that.updateLineToSelectedCluster();
      if (that.selectedGid >= 0) {
        vis.selectGroup(that.selectedGid, true);
      }

      that.serverClient.addPersonUpdateListener(onPersonUpdate); // TODO REMOVE DUPLICATE

      vis.getFirstShowDeferred().then(function () {
        setTimeout(function () {
          // that.selectedGid = -1;
          vis.deselect();
          vis.selectComment(null);
          // that.conversationTabs.gotoAnalyzeTab();
          that.conversationTabs.gotoInfoPaneTab();
        }, 0);
        that.groupSelectionView.show();
      });
    } // end initPcaVis

    this.initPcaVis = initPcaVis;

    // just a quick hack for now.
    // we may need to look into something more general
    // http://stackoverflow.com/questions/11216392/how-to-handle-scroll-position-on-hashchange-in-backbone-js-application
    var scrollTopOnFirstShow = _.once(function () {
      // scroll to top
      window.scroll(0, 0);
    });

    /* child views */
    this.tutorialModel = new Backbone.Model({
      visible: false,
      paused: false,
      step: useAboveVisTutorial ? 1 : Infinity
    });
    this.tutorialModel.on("change:step", function () {
      var step = that.tutorialModel.get("step");
      if (step === 1) {
        that.vis.showHintYou();
      } else {
        that.vis.hideHintYou();
      }
      if (step === 2) {
        that.vis.showHintOthers();
      } else {
        that.vis.hideHintOthers();
      }
    });

    var mode = VIS_MODE_VIS;
    if (useVoteMoreBlocker) {
      mode = VIS_MODE_VOTEMORE;
    } else {
      mode = VIS_MODE_VIS;
    }
    this.visModeModel = new Backbone.Model({
      visMode: -1
    });
    this.visModeModel.on("change:visMode", function () {
      var visMode = that.visModeModel.get("visMode");
      if (visMode === VIS_MODE_TUT) {
        $("#afterTutorial").hide();
        $("#voteMoreParent").hide();
        $("#visualization_parent_div").hide();
        // hide others
      }
      if (visMode === VIS_MODE_VIS) {
        // that.vis.hideHintVoteMoreBlocker();
        $("#voteMoreParent").hide();
        $("#afterTutorial").show();
        $("#visualization_parent_div").css("visibility", "visible");
        $("#visualization_parent_div").css("display", "block");
        // $("#visualization_div").css("display", "block");
        $("#visualization_parent_div").fadeIn();
        that.tutorialModel.set("visible", true);
        that.initPcaVis();
        // hide others
      }
      if (visMode === VIS_MODE_WAITING) {
        that.tutorialModel.set("visible", false);
        $("#voteMoreParent").hide();
        $("#visualization_parent_div").fadeOut();
        // hide others
      }
      if (visMode === VIS_MODE_VOTEMORE) {
        // that.vis.showHintVoteMoreBlocker();
        $("#voteMoreParent").fadeIn();
        $("#visualization_parent_div").fadeOut();
        that.tutorialModel.set("visible", false);
        // hide others
      }
    });

    setTimeout(function () {
      that.visModeModel.set("visMode", mode);
    }, 1);

    this.infoSlideViewModel = new Backbone.Model({
      numParticipants: 10000,
      numComments: this.allCommentsCollection.length
    });
    this.conversationInfoSlideView = this.addChild(
      new ConversationInfoSlideView({
        model: this.infoSlideViewModel
      })
    );

    this.voteMoreModel = new Backbone.Model({
      remaining: 0
    });
    this.voteMoreView = this.addChild(
      new VoteMoreView({
        model: this.voteMoreModel
      })
    );

    this.selectedGid = -1;
    this.groupNamesModel = new Backbone.Model({
      groups: [
        // these will be set when the pca results arrive
        // {name: 1, gid: 0},
        // {name: 2, gid: 1},
        // {name: 3, gid: 2},
        {
          name: "Majority Opinion",
          gid: -1
        }
      ],
      selectedGid: this.selectedGid,
      infoSlidePaneViewActive: true
    });
    this.groupSelectionView = this.addChild(
      new GroupSelectionView({
        model: this.groupNamesModel
      })
    );
    this.groupSelectionView.addSelectionChangedListener(function (gid) {
      that.groupNamesModel.set({
        infoSlidePaneViewActive: false
      });
      if (gid === -1) {
        that.vis.deselect();
        that.conversationTabs.gotoAnalyzeTab();
      } else {
        that.vis.selectGroup(gid);
      }
      eb.trigger(eb.clusterClicked, gid);
      // if (gid === -1) {
      //   setTimeout(function() {
      //     that.vis.showAllClustersAsActive();
      //   }, 1);
      // }
    });
    this.groupSelectionView.addInfoPaneButtonClickedListener(function () {
      $("#infoPaneTab").click();
    });

    // var gotFirstComment = (firstComment && !_.isUndefined(firstComment.txt));
    // var openToWriteTab = !gotFirstComment;
    var allowMajority = true; //this.model.get("vis_type") >= 1;
    this.conversationTabs = this.addChild(
      new ConversationTabsView({
        serverClient: serverClient,
        // openToWriteTab: openToWriteTab,
        openToAnalyzeTab: true,
        model: new Backbone.Model({
          allowMajority: allowMajority,
          showTabs: true
        })
      })
    );

    this.writingTips = this.addChild(new WritingTipsView());

    this.commentForm = this.addChild(
      new CommentFormView({
        model: new Backbone.Model({}),
        conversationModel: this.model,
        serverClient: this.serverClient,
        // collection: this.commentsByMe,
        conversation_id: conversation_id,
        wipCommentFormText: this.wipCommentFormText
      })
    );

    this.analyzeGroupModel = new Backbone.Model({
      selectedGid: this.selectedGid
    });

    this.voteMoreModel.on("change", function () {
      that.updateVisMode();
    });

    that.updateVoteRemaining();
    that.votesByMe.on("sync", function () {
      that.updateVoteRemaining();
    });
    that.votesByMe.on("change", function () {
      that.updateVoteRemaining();
    });
    that.votesByMe.on("add", function () {
      that.updateVoteRemaining();
    });

    // var doReproject = _.debounce(serverClient.updateMyProjection, 1000);

    eb.on(eb.commentSelected, function (tid) {
      if (vis) {
        vis.selectComment(tid);
      }
    });

    var updateMyProjectionAfterAddingVote = _.throttle(function () {
      setTimeout(function () {
        serverClient.updateMyProjection(that.votesByMe);
      }, 300); // wait a bit to let the dot blink before moving it.
    }, 200);

    // Wait for PCA to download, so we don't fire an event with only the blue dot.
    // That would cause the vis blocker to flash.
    this.firstMathPollResultDeferred.then(function () {
      that.votesByMe.on("add", updateMyProjectionAfterAddingVote);

      // Select "Majority Opinion" on launch.
      that.groupSelectionView.setSelectedGroup(-1);
    });

    this.commentForm.on("commentSubmitted", function () {
      // $("#"+VOTE_TAB).tab("show");
    });

    // Clicking on the background dismisses the popovers.
    this.$el.on("click", function () {
      that.destroyPopovers();
    });

    that.conversationTabs.on("beforeshow:write", function () {
      if (shouldHideVisWhenWriteTabShowing()) {
        // When we're switching to the write tab, hide the vis.
        that.hideVis();
      }
      moveVisToBottom(); // just in case
      that.showWriteHints();
    });
    that.conversationTabs.on("beforehide:write", function () {
      // When we're leaving the write tab, show the vis again.
      that.showVis();
      that.hideWriteHints();
    });
    that.conversationTabs.on("beforehide:group", function () {
      if (vis) {
        vis.deselect();
      }
      // eb.trigger(eb.commentSelected, false);
      // that.conversationTabs.doShowTabsUX();
    });
    that.conversationTabs.on("afterhide:majority", function () {
      if (vis) {
        vis.selectComment(null);
      }
    });

    that.conversationTabs.on("beforeshow:majority", function () {
      // that.showTutorial();
      if (that.shouldShowVisUnderTabs()) {
        moveVisAboveQueryResults();
      }
      // that.showVis();

      that.allCommentsCollection
        .doFetch({
          // TODO needed anymore?
          gid: that.selectedGid
        })
        .then(function () {
          //that.commentCarouselMajorityView.renderWithCarousel();
        });
    });
    that.conversationTabs.on("beforeshow:group", function () {
      if (that.shouldShowVisUnderTabs()) {
        moveVisAboveQueryResults();
      }
      // that.showVis();
      that.allCommentsCollection
        .doFetch({
          gid: that.selectedGid
        })
        .then(function () {
          // setTimeout(function() {
          //   $("#carousel").fadeIn("slow");
          // }, 100);
        });
    });
    that.conversationTabs.on("aftershow:vote", function () {
      that.initPcaVis();
    });
    that.conversationTabs.on("beforeshow:vote", function () {
      moveVisToBottom();
      // that.showVis();
      // that.showTutorial();
    });
    that.conversationTabs.on("aftershow:majority", function () {
      that.initPcaVis();
      // that.commentCarouselMajorityView.renderWithCarousel();

      if (SHOULD_AUTO_CLICK_FIRST_COMMENT) {
        $(".query_result_item").first().trigger("click");
      }
    });
    that.conversationTabs.on("aftershow:group", function () {
      that.initPcaVis();
      $(".query_result_item").first().trigger("click");
    });
    that.conversationTabs.on("aftershow:write", function () {
      // Put the comment textarea in focus (should pop up the keyboard on mobile)
      if (Utils.shouldFocusOnTextareaWhenWritePaneShown()) {
        $("#comment_form_textarea").focus();
      }
    });

    this.listenTo(this, "render", function () {
      setTimeout(function () {
        if (window.preload.firstConv.participant_count < MIN_PTPTS) {
          $("#vis_not_yet_label").show();
        }

        that.updateVis2();
        that.updateTopComments();
        that.updateHeader();

        that.updateVisMode();

        if (window.POLIS_DELPHI_ENABLED) {
          try {
            $("#polis-donate").hide();
          } catch (e) {
            console.error(e);
          }
        }

        // that.visModeModel.set("visMode", VIS_MODE_WAITING);

        $("#getDataButton").on("click", function () {
          $.get("/api/v3/dummyButton?button=getDataButton");
          setTimeout(function () {
            alert("coming soon!");
          });
        });

        $("#closeConversationButton").on("click", function () {
          $.post("/api/v3/conversation/close", {
            conversation_id: that.conversation_id
          }).then(
            function () {
              alert("Conversation closed! Writing and voting are disabled.");
              document.location.reload();
            },
            function () {
              alert("error closing conversation");
            }
          );
        });

        $("#reopenConversationButton").on("click", function () {
          $.post("/api/v3/conversation/reopen", {
            conversation_id: that.conversation_id
          }).then(
            function () {
              alert("Conversation reopened! Writing and voting are enabled.");
              document.location.reload();
            },
            function () {
              alert("error reopening conversation");
            }
          );
        });

        $("#nextTutorialStepButton").on("click", function () {
          that.vis.tutorialNextClicked();
        });

        scrollTopOnFirstShow();

        if (!display.xs() && !display.sm() && that.shouldAffixVis) {
          $("#visualization_div").affix({
            offset: {
              top: 150 //will be set dynamically
            }
          });
        }

        configureGutters();
        var windowWidth = $(window).width();

        function resizeVis() {
          var windowWidthNew = $(window).width();
          if (windowWidth !== windowWidthNew) {
            windowWidth = windowWidthNew;
            configureGutters();
            initPcaVis();
          }
        }
        var resizeVisWithDebounce = _.debounce(resizeVis, 500);

        if (isIE8) {
          // Can't listen to the "resize" event since IE8 fires a resize event whenever a DOM element changes size.
          // http://stackoverflow.com/questions/1852751/window-resize-event-firing-in-internet-explorer
          setTimeout(initPcaVis, 10); // give other UI elements a chance to load
          // document.body.onresize = _.debounce(initPcaVis, 1000)
        } else {
          setTimeout(initPcaVis, 10); // give other UI elements a chance to load

          // This need to happen quickly, so no debounce
          $(window).resize(function () {
            if (that.shouldShowVisUnderTabs()) {
              // wait for layout
              setTimeout(moveVisAboveQueryResults, 10);
            } else {
              // wait for layout
              setTimeout(moveVisToBottom, 10);
            }

            resizeVisWithDebounce();
          });
        }
      }, 0); // end listenTo "render"
    });
    this.render();

    // Prefetch the comments to speed up the first click on a group.
    // (we don't want to slow down page load for this, so deferring,
    //  but we don't want to wait until the user clicks the hull)
    setTimeout(function () {
      that.allCommentsCollection.doFetch({});
    }, 3000);
  } // end initialize
});
